"""
数据库配置和连接管理
支持 MySQL 和 SQLite 数据库的异步连接
"""

from collections.abc import AsyncGenerator
from datetime import datetime

from sqlalchemy import DateTime, Integer, func
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column

from src.config import (
    DATABASE_URL,
    ECHO_SQL,
    MAX_OVERFLOW,
    POOL_RECYCLE,
    POOL_SIZE,
    POOL_TIMEOUT,
)

# 创建异步引擎
engine = create_async_engine(
    DATABASE_URL,
    echo=ECHO_SQL,  # 在开发环境中打印 SQL 语句
    future=True,
    pool_size=POOL_SIZE,
    max_overflow=MAX_OVERFLOW,
    pool_timeout=POOL_TIMEOUT,
    pool_recycle=POOL_RECYCLE,
)

# 创建异步会话工厂
AsyncSessionLocal = async_sessionmaker(
    bind=engine, class_=AsyncSession, expire_on_commit=False, autoflush=False
)


async def get_db() -> AsyncGenerator[AsyncSession]:
    """
    获取数据库会话的依赖函数
    用于 FastAPI 依赖注入
    """
    async with AsyncSessionLocal() as session:
        try:
            yield session
        finally:
            await session.close()


async def init_db() -> None:
    """
    初始化数据库
    创建所有表
    """
    pass


async def close_db() -> None:
    """
    关闭数据库连接
    """
    await engine.dispose()


def _current_member_id() -> int:
    from src.contexts import get_user

    member = get_user()
    return member.id if member else 0


# 创建声明性基类
class Base(DeclarativeBase):
    """所有数据库模型的基类"""

    id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), server_default=func.now()
    )
    updated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), onupdate=func.now(), server_default=func.now()
    )
    created_by: Mapped[int] = mapped_column(
        Integer,
        comment="创建人ID",
        nullable=False,
        server_default="0",
        default=_current_member_id,
    )
    updated_by: Mapped[int] = mapped_column(
        Integer,
        comment="创建人ID",
        nullable=False,
        server_default="0",
        default=_current_member_id,
        onupdate=_current_member_id,
    )
